home *** CD-ROM | disk | FTP | other *** search
/ Ultimedia 1 / Ultimedia 1.iso / tools / sonstiges / easysound / easysound.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-08-05  |  13.2 KB  |  465 lines

  1. /*********************************************************************
  2. * Play Sound V1.1 - written with the aid of the 2.0 RKRMs in 1993 for
  3. * my PingPong game. You may use it in your programs for free. Please
  4. * read the docs for more information.
  5. *********************************************************************/
  6.  
  7. /// "Includes, Defines, Typedefs, ..."
  8. #include <clib/alib_protos.h>
  9. #include <clib/exec_protos.h>
  10. #include <clib/graphics_protos.h>
  11. #include <clib/dos_protos.h>
  12. #include <exec/types.h>
  13. #include <exec/memory.h>
  14. #include <libraries/dos.h>
  15. #include <devices/audio.h>
  16. #include <graphics/gfxbase.h>
  17. #include <stdio.h>
  18. #include <string.h>
  19. #include "easysound.h"
  20.  
  21. #define Prototype   extern
  22.  
  23. #define CLOCK_PAL   3579545
  24. #define CLOCK_NTSC  3546895
  25.  
  26. struct IOAudio *IO[] = {
  27.     NULL,       // All channels are switched off by default
  28.     NULL, 
  29.     NULL, 
  30.     NULL
  31. };
  32.  
  33. struct Voice8Header {
  34.     ULONG  oneShotHiSamples;  // high octave 1-shot samples
  35.     ULONG  repeatHiSamples;   // high octave repeat samples
  36.     ULONG  samplesPerHiCycle; // high octave samples per cycle
  37.     UWORD  samplesPerSec;     // sampling rate
  38.     UBYTE  ctOctave;          // number of octaves
  39.     UBYTE  sCompression;      // Compression mode
  40.     LONG   vol;               // Playback volume
  41. } SampleHeader;
  42.  
  43. struct HEADER {
  44.     UBYTE   Form[4];
  45.     long    length;
  46.     UBYTE   Type[4];
  47. } Header;
  48.  
  49. struct SoundInfo {
  50.     BYTE *SoundBuffer;  // Buffer to hold the waveform
  51.     UWORD RecordRate;   // Record rate
  52.     ULONG FileLength;   // Length of wave
  53.     UBYTE channel_bit;  // Channel to use
  54. };
  55.  
  56. UBYTE version_tag[] = "\0$VER: EasySound V1.1 (7.8.94) ";
  57. ///
  58. /// "Prototypes"
  59. Prototype BOOL PlayIff (struct SoundInfo *info, UWORD vol, UBYTE chan, BYTE prio, WORD drate, UWORD repeat, ULONG start, ULONG time, BOOL wait);
  60.  
  61. Prototype void StopIff (UBYTE chan);
  62.  
  63. Prototype LONG GetClockSpeed(void);
  64.  
  65. Prototype void RemoveIff(struct SoundInfo *info);
  66.  
  67. Prototype struct SoundInfo *LoadIff(STRPTR name);
  68.  
  69. Prototype void FindChunk(BPTR file, char *searchchunk);
  70. ///
  71. /// "PlayIff"
  72. /****** EasySound/PlayIff **********************************************
  73. *
  74. *   NAME
  75. *       PlayIff -- Play an IFF sample
  76. *
  77. *   SYNOPSIS
  78. *       success = PlayIff(info, vol, chan, prio, drate, times, start,
  79. *                         time, wait)
  80. *       BOOL PlayIff
  81. *           (struct SoundInfo *, UWORD, UBYTE, BYTE, WORD, UWORD, ULONG,
  82. *            ULONG, BOOL)
  83. *
  84. *   FUNCTION
  85. *       Plays an IFF sample. The sample has to be converted to an include
  86. *       file with the aid of the external program 'iff2src'. The resulting 
  87. *       sound data has to be placed in chip memory using e.g. the __chip 
  88. *       keyword.
  89. *
  90. *   INPUTS
  91. *       info        - A (struct SoundInfo *) pointer to the structure.
  92. *       vol         - The volume of the sound (between 0 and 64).
  93. *       chan        - The channel on which the sample will be played, can
  94. *                     be either left or right ;-) . You may use the magic
  95. *                     cookies L0, L1, R0, R1.
  96. *       prio        - State a priority for the sample. (may be something
  97. *                     between -127 and 128.
  98. *       drate       - The sample rate is already stored in the SoundInfo
  99. *                     structure. If you don't want to change the rate,
  100. *                     leave this value 0.
  101. *       times       - How many times do you want this sound to be played.
  102. *                     If you set this value to 0 the sound will be played
  103. *                     nonstop. (You may stop it with StopIff)
  104. *       start       - Where do you want to start the sample, leave this
  105. *                     value to 0 if you want to start at the beginning.
  106. *       time        - How long do you want to play this sound, leave this
  107. *                     value to 0 if you want to play the whole sample.
  108. *       wait        - If you set this value to TRUE your program will wait
  109. *                     until the Sample is played. If it's set to FALSE your
  110. *                     program will continue to run while the sample is
  111. *                     played.
  112. *
  113. *   RESULT
  114. *       success     - Returns TRUE if the sound was played with success,
  115. *                     otherwise the function will return FALSE.
  116. *
  117. *   EXAMPLE
  118. *       PlayIff(&splat_data,64,L0,-35,0,1,0,0,0);
  119. *
  120. *   SEE ALSO
  121. *       StopIff, RemoveIff, LoadIff
  122. *************************************************************************/
  123. BOOL PlayIff (struct SoundInfo *info, UWORD vol, UBYTE chan, BYTE prio,
  124.               WORD drate, UWORD times, ULONG start, ULONG time, BOOL wait) {
  125.  
  126.     LONG clock;
  127.     BYTE error;
  128.     struct MsgPort *port;
  129.     UWORD period;
  130.  
  131.     /*
  132.      * Stop the sound on this channel first (if one is still in use)
  133.      */
  134.     StopIff(chan);
  135.  
  136.     /*
  137.      * Get the ClockSpeed depend on wheter you use a PAL or NTSC Amiga
  138.      */
  139.     clock = GetClockSpeed();
  140.  
  141.     /*
  142.      * Prepare the complete device stuff.
  143.      */
  144.  
  145.     period = clock/info->RecordRate+drate;
  146.     
  147.     /*
  148.      * Create a message port
  149.      */
  150.     port = (struct MsgPort *)CreatePort(NULL, 0);
  151.     if(!port) {
  152.         return(FALSE);
  153.     }
  154.  
  155.     /*
  156.      * Create an IO request:
  157.      */
  158.     IO[chan]=(struct IOAudio *)CreateExtIO(port,sizeof(struct IOAudio));
  159.     if(!IO[chan]) {
  160.       DeletePort(port);
  161.       return(FALSE);
  162.     }
  163.     
  164.     /*
  165.      * Init Audio struct
  166.      */
  167.     IO[chan]->ioa_Request.io_Message.mn_Node.ln_Pri = prio;
  168.     info->channel_bit = 1<<chan;
  169.     IO[chan]->ioa_Data = &(info->channel_bit);
  170.     IO[chan]->ioa_Length = sizeof(UBYTE);
  171.  
  172.     /*
  173.      * And now open the Audio Device
  174.      */
  175.     error =  OpenDevice(AUDIONAME, 0, (struct IORequest *)IO[chan], 0);
  176.     if(error) {
  177.         DeleteExtIO((struct IORequest *)IO[chan]);
  178.         DeletePort(port);
  179.         IO[chan] = NULL;
  180.         return(FALSE);
  181.     }
  182.  
  183.     IO[chan]->ioa_Request.io_Flags = ADIOF_PERVOL;
  184.     IO[chan]->ioa_Request.io_Command = CMD_WRITE;
  185.     IO[chan]->ioa_Period = period;
  186.     IO[chan]->ioa_Volume = vol;
  187.     IO[chan]->ioa_Cycles = times;
  188.  
  189.     if(time)
  190.         IO[chan]->ioa_Length = time;
  191.     else
  192.         IO[chan]->ioa_Length = info->FileLength;
  193.  
  194.     IO[chan]->ioa_Data = info->SoundBuffer + start;
  195.  
  196.     /*
  197.      * Here's the output stuff
  198.      */
  199.     BeginIO((struct IORequest *)IO[chan]);
  200.     if(wait)
  201.         WaitIO((struct IORequest *)IO[chan]);
  202.     return(TRUE);
  203. }
  204. ///
  205. /// "StopIff"
  206. /****** EasySound/StopIff **********************************************
  207. *
  208. *   NAME
  209. *       StopIff -- Stop an IFF sample
  210. *
  211. *   SYNOPSIS
  212. *       StopIff(chan)
  213. *
  214. *       void StopIff (UBYTE)
  215. *
  216. *   FUNCTION
  217. *       Will stop the sound on the specified audio channel. It'll close the
  218. *       the devices and ports and free the allocated memory. If you call 
  219. *       this function without any sound being played it'll simply return.
  220. *
  221. *   INPUTS
  222. *       chan        - The channel that should be stopped. You may use the
  223. *                     magic cookies L0,L1,R0,R1 for this task.
  224. *
  225. *   SEE ALSO
  226. *       PlayIff, RemoveIff, LoadIff
  227. ************************************************************************/
  228. void StopIff (UBYTE chan) {
  229.  
  230.     /*
  231.      * Test if this channel is REALLY(!) in use, otherwise this function
  232.      * will simply return without doing anything.
  233.      */
  234.     if(IO[chan]) {
  235.         AbortIO((struct IORequest *)IO[chan]);
  236.  
  237.         if(IO[chan]->ioa_Request.io_Device)
  238.             CloseDevice((struct IORequest *)IO[chan]);
  239.  
  240.         if(IO[chan]->ioa_Request.io_Message.mn_ReplyPort)
  241.             DeletePort(IO[chan]->ioa_Request.io_Message.mn_ReplyPort);
  242.  
  243.         DeleteExtIO((struct IORequest *)IO[chan]);
  244.         IO[chan] = NULL;
  245.     }
  246. }
  247. ///
  248. /// "GetClockSpeed"
  249. /****** EasySound/GetClockSpeed *****************************************
  250. *
  251. *   NAME
  252. *       GetClockSpeed -- Determine the clock speed for PAL / NTSC
  253. *
  254. *   SYNOPSIS
  255. *       clock = GetClockSpeed()
  256. *
  257. *       LONG GetClockSpeed( void )
  258. *
  259. *   FUNCTION
  260. *       This function returns the clockspeed for e.g samples depending
  261. *       on the system you use (NTSC or PAL).
  262. *
  263. *   SEE ALSO
  264. *       RKRM, Guru Book page 62/63
  265. *************************************************************************/
  266. LONG GetClockSpeed() {
  267.  
  268.     struct GfxBase *GfxBase;
  269.     LONG clockspeed = CLOCK_PAL;
  270.  
  271.     GfxBase = (struct GfxBase *)OpenLibrary("graphics.library",0);
  272.  
  273.     if (GfxBase) {
  274.         if (GfxBase->DisplayFlags & NTSC)
  275.             clockspeed = CLOCK_NTSC;
  276.  
  277.         if (GfxBase->DisplayFlags & PAL)
  278.             clockspeed = CLOCK_PAL;
  279.  
  280.         CloseLibrary((struct Library *)GfxBase);
  281.     }
  282.  
  283.     return clockspeed;
  284. }
  285. ///
  286. /// "RemoveIff"
  287. /****** EasySound/RemoveIff **********************************************
  288. *
  289. *   NAME
  290. *       RemoveIff -- Remove a previous loaded Sound.
  291. *
  292. *   SYNOPSIS
  293. *       RemoveIff(info)
  294. *
  295. *       void RemoveIff (struct SoundInfo *)
  296. *
  297. *   FUNCTION
  298. *       Will flush a loaded sample and free the memory.
  299. *
  300. *   INPUTS
  301. *       info        - Pointer to the SoundInfo structure
  302. *
  303. *   SEE ALSO
  304. *       PlayIff, StopIff, LoadIff
  305. ************************************************************************/
  306. void RemoveIff(struct SoundInfo *info) {
  307.     if (info) {
  308.         FreeMem(info->SoundBuffer, info->FileLength);
  309.         FreeMem(info, sizeof(struct SoundInfo));
  310.     }
  311. }
  312. ///
  313. /// "LoadIff"
  314. /****** EasySound/LoadIff **********************************************
  315. *
  316. *   NAME
  317. *       LoadIff -- Load an external sample in the chip memory
  318. *
  319. *   SYNOPSIS
  320. *       info = LoadIff(filename)
  321. *
  322. *       struct SoundInfo *LoadIff(STRPTR)
  323. *
  324. *   FUNCTION
  325. *       Loads an external 8svx sample in chip memory and returns a pointer
  326. *       to the SoundInfo structure or NULL if the whole thing failed.
  327. *
  328. *   INPUTS
  329. *       filename    - Name of the file, eventually with path.
  330. *
  331. *   SEE ALSO
  332. *       PlayIff, StopIff, LoadIff
  333. ************************************************************************/
  334. struct SoundInfo *LoadIff(STRPTR name) {
  335.  
  336.     BPTR    file;
  337.     struct  SoundInfo       *info;
  338.  
  339.     /*
  340.      * Allocate the memory for the SoundInfo structure and clear it
  341.      */
  342.     info = (struct SoundInfo *)AllocMem(sizeof(struct SoundInfo), MEMF_CLEAR);
  343.     if (!info) {
  344.         return (NULL);
  345.     }
  346.  
  347.     /*
  348.      * Open the file (read mode) and exit if the file can't be opened
  349.      * (remember: This is compiled with DICE, this compiler will handle
  350.      * the opening and closing of the Dos Library for me when finding the
  351.      * first DosLib call, in this case it's Open() )
  352.      */
  353.     file = Open(name,MODE_OLDFILE);
  354.     if (!file) {
  355.         FreeMem(info, sizeof(struct SoundInfo));
  356.         return (NULL);
  357.     }
  358.  
  359.     /*
  360.      * Read the first 12 bytes, it's the IFF Header and we can take a look
  361.      * at the last 4 bytes to see if it's an 8SVX file. The first 4 bytes
  362.      * contains the FORM chunk, the 2nd 4 bytes will give you the length of
  363.      * this file and the last 4 bytes contain the identifier (8SVX, ILBM,
  364.      * CTLG, ...)
  365.      */
  366.     Read(file, &Header, sizeof(Header));
  367.  
  368.     if (strcmp(Header.Type,"8SVX") != 0) {
  369.         FreeMem(info, sizeof(struct SoundInfo));
  370.         Close(file);
  371.         return (NULL);
  372.     }
  373.     
  374.     /*
  375.      * Search for the VHDR chunk, it marks the position of the sample header
  376.      * We need it to calculate the record rate and the sample length.
  377.      */
  378.     FindChunk(file, "VHDR");
  379.     Read(file, &SampleHeader, sizeof(SampleHeader));
  380.  
  381.     info->FileLength = SampleHeader.oneShotHiSamples + SampleHeader.repeatHiSamples;
  382.     info->RecordRate = SampleHeader.samplesPerSec;
  383.  
  384.     /*
  385.      * Exit if the FileLength or the RecordRate is 0, something must be
  386.      * wrong in the file.
  387.      */
  388.     if (info->FileLength == 0 || info->RecordRate == 0) {
  389.         FreeMem(info, sizeof(struct SoundInfo));
  390.         Close(file);
  391.         return (NULL);
  392.     }
  393.  
  394.     /*
  395.      * The old FutureSound format stored the RecordRate in KHz instead of 
  396.      * Hz. FutureSound Recordrates are smaller than 100, therefor we'll have
  397.      * to change them to Hz. (1KHz === 1000Hz).
  398.      */
  399.     if (info->RecordRate < 100)
  400.         info->RecordRate *= 1000;
  401.  
  402.     /*
  403.      * Now that we have received the length of the sample we're ready to
  404.      * allocate the Buffer for the sample. Remember: It must be placed in
  405.      * Chipmem.
  406.      */
  407.     info->SoundBuffer = (BYTE *)AllocMem(info->FileLength,MEMF_CHIP | MEMF_CLEAR);
  408.     if (!info->SoundBuffer) {
  409.         FreeMem(info, sizeof(struct SoundInfo));
  410.         Close(file);
  411.         return (NULL);
  412.     }
  413.  
  414.     /*
  415.      * Ok, allocation the buffer was successfully. Let's fill it with the
  416.      * sample data.
  417.      */
  418.     FindChunk(file, "BODY");
  419.     Read(file, info->SoundBuffer, info->FileLength);
  420.  
  421.     Close(file);
  422.  
  423.     return info;
  424. }
  425. ///
  426. /// "FindChunk"
  427. /****i* EasySound/FindChunk **********************************************
  428. *
  429. *   NAME
  430. *       FindChunk -- Search for a special chunk in an IFF file.
  431. *
  432. *   SYNOPSIS
  433. *       FindChunk(file, search)
  434. *
  435. *       void FindChunk(BPTR, char *)
  436. *
  437. *   FUNCTION
  438. *       Search for a special chunk in an IFF file and set the File
  439. *       pointer on this chunk.
  440. *
  441. *   INPUTS
  442. *       file        - Pointer on a file opened with Open()
  443. *       search      - An Iff chunk to search for (e.g ILBM, 8SVX, BODY)
  444. *
  445. *
  446. *   SEE ALSO
  447. *       dos.library/Open
  448. ************************************************************************/
  449. void FindChunk(BPTR file, char *searchchunk) {
  450.  
  451.     UBYTE chunk[4];
  452.  
  453.     /*
  454.      * Rewind the file to the beginning.
  455.      */
  456.     Seek(file, 0, OFFSET_BEGINNING);
  457.  
  458.     while (strcmp(chunk, searchchunk) != 0) {
  459.         Read(file, &chunk, sizeof(chunk));
  460.     }
  461.     Read(file, &chunk, sizeof(chunk));
  462. }
  463. ///
  464.  
  465.